//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package user_api_serv

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/user_dao"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/user_api"
	"github.com/dchest/uniuri"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func getAtomGitAccessToken(clientId, clientSecret, code string) (string, string, error) {
	jsonData, err := json.Marshal(map[string]string{
		"client_id":     clientId,
		"client_secret": clientSecret,
		"code":          code,
	})
	if err != nil {
		return "", "", err
	}

	res, err := http.Post("https://api.atomgit.com/login/oauth/access_token", "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return "", "", err
	}
	defer res.Body.Close()
	resData, err := io.ReadAll(res.Body)
	if err != nil {
		return "", "", err
	}
	resObj := map[string]any{}
	err = json.Unmarshal(resData, &resObj)
	if err != nil {
		return "", "", err
	}
	//失败{"errorCode":"system_not_found","message":"User authorization can not found by code","success":false,"traceId":"0a06d77e17103789731548167d001b"}l
	//成功{"access_token":"atu_95e393494aae57fe194096c48116e54f","expires_in":1710407865714,"refresh_token":"refresh_7e9cd2fb3a206e1e9c5c12ae2b198a78","refresh_token_expires_in":1726276665714}l
	errMsg, ok := resObj["message"]
	if ok {
		return "", "", fmt.Errorf(errMsg.(string))
	}
	accessToken := resObj["access_token"]
	refreshToken := resObj["refresh_token"]
	if accessToken == nil || refreshToken == nil {
		return "", "", fmt.Errorf("wrong response")
	}
	return accessToken.(string), refreshToken.(string), nil
}

func refreshAtomGitAccessToken(clientId, clientSecret, refreshToken string) (string, string, error) {
	jsonData, err := json.Marshal(map[string]string{
		"client_id":     clientId,
		"client_secret": clientSecret,
		"grant_type":    "refresh_token",
		"refresh_token": refreshToken,
	})
	if err != nil {
		return "", "", err
	}

	res, err := http.Post("https://api.atomgit.com/login/oauth/access_token", "application/json", bytes.NewBuffer(jsonData))
	if err != nil {
		return "", "", err
	}
	defer res.Body.Close()
	resData, err := io.ReadAll(res.Body)
	if err != nil {
		return "", "", err
	}
	resObj := map[string]any{}
	err = json.Unmarshal(resData, &resObj)
	if err != nil {
		return "", "", err
	}
	//失败{"errorCode":"token_expire","message":"refresh token is wrong or expired","success":false,"traceId":"0a07b50217103838687142442d001b"}
	//成功{"access_token":"atu_a2f8cae3634a8ba2f1b8dbe0df238f95","expires_in":1710412826068,"refresh_token":"refresh_4be749ff13bf0fc1d14ab56d4dd0cb52","refresh_token_expires_in":1726281626068}
	errMsg, ok := resObj["message"]
	if ok {
		return "", "", fmt.Errorf(errMsg.(string))
	}
	accessToken := resObj["access_token"]
	newRefreshToken := resObj["refresh_token"]
	if accessToken == nil || newRefreshToken == nil {
		return "", "", fmt.Errorf("wrong response")
	}
	return accessToken.(string), newRefreshToken.(string), nil
}

func getAtomGitUserName(accessToken string) (string, string, string, error) {
	req, err := http.NewRequest("GET", "https://api.atomgit.com/user/info", nil)
	if err != nil {
		return "", "", "", err
	}
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Authorization", "Bearer "+accessToken)
	res, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", "", "", err
	}
	defer res.Body.Close()
	resData, err := io.ReadAll(res.Body)
	if err != nil {
		return "", "", "", err
	}
	resObj := map[string]any{}
	err = json.Unmarshal(resData, &resObj)
	if err != nil {
		return "", "", "", err
	}
	// 失败返回
	// {
	// 	"error": "unauthorized",
	// 	"error_description": "Requires authentication"
	// }
	// 成功返回
	// {
	// 	"login": "openlinksaas",
	// 	"id": "64fae54f49d9355e7a863eb6",
	// 	"url": "https://api.atomgit.com/users/openlinksaas",
	// 	"name": "openlinksaas",
	// 	"company": "深圳市同心圆网络有限公司",
	// 	"blog": "https://www.linksaas.pro",
	// 	"location": "广州",
	// 	"email": "panleiming@linksaas.pro",
	// 	"bio": "",
	// 	"avatar_url": "https://file.atomgit.com/uploads/user/1694222084215_2176.png",
	// 	"html_url": "https://atomgit.com/openlinksaas",
	// 	"public_repos": 10,
	// 	"created_at": "2023-09-08 17:11:43",
	// 	"updated_at": "2024-02-21 17:20:20",
	// 	"total_private_repos": 0,
	// 	"owned_private_repos": 0
	// }

	errDesc, ok := resObj["error_description"]
	if ok {
		return "", "", "", fmt.Errorf(errDesc.(string))
	}
	login := resObj["login"]
	name := resObj["name"]
	avatarUrl := resObj["avatar_url"]

	if login == nil || name == nil || avatarUrl == nil {
		return "", "", "", fmt.Errorf("wrong response")
	}
	return "atomgit:" + login.(string), name.(string), avatarUrl.(string), nil
}

func (apiImpl *UserApiImpl) loginAtomGit(ctx context.Context, req *user_api.LoginRequest) (*user_api.LoginResponse, error) {
	//获取accessToken
	accessToken, refreshToken, err := getAtomGitAccessToken(apiImpl.servCfg.AtomGit.ClientId, apiImpl.servCfg.AtomGit.ClientSecret, req.Passwd)
	if err != nil {
		return nil, err
	}
	//获取用户信息
	userName, displayName, logoUri, err := getAtomGitUserName(accessToken)
	if err != nil {
		return nil, err
	}
	//检查用户是否存在
	userInfoItem, err := user_dao.UserInfoDao.GetByName(ctx, userName)
	if err != nil { //用户不存在
		dbSess, err := dao.StartSession()
		if err != nil {
			return nil, err
		}
		defer dao.EndSession(dbSess)

		userId, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
			userId := uuid.NewString()
			err = api_common.CreateUser(sessCtx, userId, userName, displayName, logoUri, "", false, user_api.USER_TYPE_USER_TYPE_ATOM_GIT)
			if err != nil {
				return "", err
			}
			return userId, nil
		})
		if err != nil {
			return nil, err
		}
		userInfoItem, err = user_dao.UserInfoDao.Get(ctx, userId.(string))
		if err != nil {
			return &user_api.LoginResponse{
				Code:   user_api.LoginResponse_CODE_WRONG_USERNAME,
				ErrMsg: "用户不存在",
			}, nil
		}
	} else {
		if userInfoItem.BasicInfo.DisplayName != displayName || userInfoItem.BasicInfo.LogoUri != logoUri {
			err = user_dao.UserInfoDao.UpdateBasicInfo(ctx, userInfoItem.UserId, &user_dao.BasicUserInfoDbItem{
				DisplayName: displayName,
				LogoUri:     logoUri,
			})
			if err != nil {
				return nil, err
			}
		}
	}
	userInfoItem.BasicInfo.DisplayName = displayName
	userInfoItem.BasicInfo.LogoUri = logoUri
	//创建会话
	secretItem, err := user_dao.UserSecretDao.Get(ctx, userInfoItem.UserId)
	if err != nil {
		secretItem = &user_dao.UserSecretDbItem{}
	}
	//创建会话
	sessionId := uniuri.NewLen(32) + strings.ReplaceAll(uuid.NewString(), "-", "")

	dao.CacheDao.SetSession(ctx, &dao.SessionDbItem{
		SessionId:         sessionId,
		UserId:            userInfoItem.UserId,
		UserName:          userInfoItem.UserName,
		DisplayName:       userInfoItem.BasicInfo.DisplayName,
		LogoUri:           userInfoItem.BasicInfo.LogoUri,
		UserType:          uint32(user_api.USER_TYPE_USER_TYPE_ATOM_GIT),
		TestAccount:       userInfoItem.TestAccount,
		ExtraAccessToken:  accessToken,
		ExtraRefreshToken: refreshToken,
		ExtraLastRefresh:  time.Now().Unix(),
	})

	return &user_api.LoginResponse{
		Code:       user_api.LoginResponse_CODE_OK,
		SessionId:  sessionId,
		UserInfo:   userInfoItem.ToUserInfo(),
		UserSecret: secretItem.Secret,
		ExtraToken: accessToken,
	}, nil
}
